package com.xiao.service.impl;

import com.xiao.domain.ResponseResult;
import com.xiao.domain.constants.RedisConstants;
import com.xiao.domain.pojo.BlogSysUser;
import com.xiao.domain.pojo.LoginUser;
import com.xiao.service.BlogLoginService;
import com.xiao.utils.BeanCopyUtils;
import com.xiao.utils.JwtUtil;
import com.xiao.utils.RedisCache;
import com.xiao.domain.vo.BlogUserLoginVo;
import com.xiao.domain.vo.UserInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Service
public class BlogLoginServiceImpl implements BlogLoginService {
    @Autowired
    private AuthenticationManager authenticationManager; // 因为 blog-blog 和 blog-framework 是父子关系,父工程不能访问子工程，因此这里爆红，不过没关系，只要子工程能访问即可

    @Autowired
    private RedisCache redisCache;

    @Override
    public ResponseResult login(BlogSysUser blogSysUser) { // BlogSysUser 是实体类 下面 的 LoginUser 是 登入时用的 实体类 不一样
        // 1. 使用 token 封装 登录信息
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(blogSysUser.getUserName(), blogSysUser.getPassword());

        // 2. 利用 token 生成 Authentication 对象
        Authentication authenticate = authenticationManager.authenticate(token);
        // 3. 如果 authenticate 对象为 null 则 抛出异常
        if (Objects.isNull(authenticate)){// authenticate==null
            throw new RuntimeException("运行时异常: 用户名错误或密码错误"); // 抛出异常后，下面就不会执行
        }
        // 4. 利用 authenticate 创建 登入对象
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        // 5. 利用登入对象，提取登入信息
        System.out.println("-------00------");
        Long userId = loginUser.getBlogSysUser().getId();
        System.out.println("-------01------");
        String jwt = JwtUtil.createJWT(String.valueOf(userId));
        System.out.println("-------02------");
        // 6. 把登入信息存入 Redis
        redisCache.setCacheObject(RedisConstants.BLOG_LOGIN_PREFIX+userId,loginUser);
        // 7. 把 token 和 userinfo 封装后 返回
        UserInfoVo userInfo = BeanCopyUtils.copyBean(loginUser.getBlogSysUser(), UserInfoVo.class);// 把 loginUser 中的  blogSysUser 封装成 VO
        BlogUserLoginVo blogUserLoginVo = new BlogUserLoginVo(jwt, userInfo);
        // 8. 封装成 ResponseResult 后 返回
        ResponseResult responseResult = ResponseResult.okResult(blogUserLoginVo);
        return responseResult;
    }

    @Override
    public ResponseResult logout() {
        //1. 获取 token 解析获取 userId   （这里是 因为 我们之前使用 JwtAuthenticationTokenFilter 在登录时存储在 SecurityContextHolder.getContext() 中 所以这里能提取到）
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        LoginUser loginUser = (LoginUser)authentication.getPrincipal();

        // 2. 获取用户Id
        Long userId = loginUser.getBlogSysUser().getId();

        // 3. 删除 redis 中用户的信息
        redisCache.deleteObject(RedisConstants.BLOG_LOGIN_PREFIX+userId);// 根据键名称删除

        // 4. 返回统一响应，默认 200 操作成功
        ResponseResult result = ResponseResult.okResult();
        return result;
    }
}
